#!/usr/bin/env python

"""
An echo client that allows the user to send multiple lines to the server.
Entering a blank line will exit the client.
"""

import getopt
import socket
import sys
import select
import time
import os
import libnet
from libnet.constants import * 
import pycap.capture
from threading import Thread

size = 1024
ADDR=(0,0)
_thread_invoked=None
_run_main=None


class recv_class(Thread):

    def __init__(self,cli_sock,serv_ip,serv_port,cli_ip,cli_port,p):
        Thread.__init__(self)
        self.cli_sock = cli_sock
        self.serv_ip = serv_ip
        self.serv_port = serv_port
        self.cli_ip = cli_ip
        self.cli_port = cli_port
        self.p = p
        self.i=0
        
    def run(self):
        global _thread_invoked
        global _run_main
        packet=None

        while(_thread_invoked==1):
            if(packet != None):
                #print packet
                if(packet[1].source == self.serv_ip and\
                   packet[1].destination == self.cli_ip and\
                   packet[1].protocol == 17 and\
                   packet[2].sourceport == int(self.serv_port) and\
                   packet[2].destinationport == int(self.cli_port)):
                    sys.stdout.write('%')   
                    sys.stdout.flush()

                    print packet[3]
                    if(packet[3]=='\\exit'):
                        _run_main=0
                        print packet[3]
                        sys.exit()
                    sys.stdout.write('%')   
                    sys.stdout.flush()
                packet=self.p.next()
            else:
                packet=self.p.next()
                time.sleep(1)
        sys.exit()        
        
def send_packet(cli_sock,data,dest_addr_tup,cli_port):
    dest_ip = dest_addr_tup[0]
    dest_port = dest_addr_tup[1] 
    
    l=libnet.context(RAW4, device='lo')
    #dst_ip=l.get_ipaddr4()
    dst_ip=l.name2addr4(dest_ip,DONT_RESOLVE)
    udp_tag=l.build_udp(dp=int(dest_port),sp=int(cli_port),payload=data)

    ipv4_tag=l.autobuild_ipv4(len=IPV4_H+UDP_H, prot=IPPROTO_UDP, dst=dst_ip)
    l.write()
    
def establish_connection(optlist):
    myserver=optlist[1]
    myserverport=int(optlist[2])
    myname=optlist[3]
    myport=int(optlist[4])
    
    ADDR=(myserver,myserverport)
    print "ADDR: ",ADDR
    
    host = myserver
    port = myserverport
    
    print "[CONSOLE] ***Client now Started***\n"
    print "[CONSOLE] Connecting to server @%s, PORT: %d" %(host,port)
    s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
    s.bind(('',myport))
    print "[CONSOLE] Client Socket Created\n"
    
    """Register with server"""
    print "[CONSOLE] Registering with the server"
    #s.sendto('#'+myname,ADDR) FIXME
    send_packet(s,'#'+myname,ADDR,myport)
    data,junk_tup = s.recvfrom(size)
    print data
    print junk_tup
    if (data=='done'):
        print "[CONSOLE] Registered with the server\n"
        print "[CONSOLE] Connected as %s via port %d" %(myname,myport)
    else:
        print "[CONSOLE]Registration failed. Check server IP address and port no."
        sys.exit()

    return s


def check_special_command(sp_str,mysock,MYADDR,myport,th):    
    global _run_main
    global _thread_invoked

    if('\exit' in sp_str):
        #mysock.sendto('\exit',MYADDR) FIXME
        send_packet(mysock,'\exit',MYADDR,myport)
        print "[CONSOLE] Exit Command detected. Closing connection"
        _run_main = 0 
        _thread_invoked = 0
        #mysock.close()
        #sys.exit()
        
    
def usage():
    print "USAGE:"
    sys.exit()

def clrscr():
	"""This function clears the screen according to the OS it is on."""
	if os.name == "posix":
		os.system('clear')
	else:
		os.system('CLS')

def mygetopt(myargv):
    
    if(len(myargv) > 2):
            opt,args = getopt.getopt(myargv[1:],"h:",['serverip=','serverport=','clientport=','clientname='])	
            for option,value in opt:
                    if option == "-h":
                            usage()
                    elif option == "--serverip":
                            myserver=value
                    elif option in "--serverport":
                            myserverport=value
                    elif option in "--clientname":
                            myname=value
                    elif option in "--clientport":
                            myport=value
                    else:
                            print "Unhandled option"
                            usage()
    else:
            usage()

    return [1,myserver,myserverport,myname,myport]

def main():
    clrscr()
    global _thread_invoked
    global _run_main
    optlist=[]
    optlist=mygetopt(sys.argv)    
    
    cli_sock = establish_connection(optlist)

    myserver = optlist[1]
    myserverport = int(optlist[2])
    myname = optlist[3]
    myport = optlist[4]
    
    myIP='127.0.0.1'
    
    ADDR=(myserver,myserverport)
    inputx = [cli_sock,sys.stdin]
    
    
    p = pycap.capture.capture(device='lo')
    sys.stdout.write('%')   
    sys.stdout.flush()
 
    _thread_invoked = 0
    _run_main = 1
    th=None
    
    _thread_invoked=1
    th = recv_class(cli_sock,myserver,myserverport,myIP,myport,p)
    th.start()
                    
    while (_run_main):    
        inputready,outputready,exceptready = select.select(inputx,[],[])

        for tmp in inputready:
            if tmp == cli_sock:
                # handle the server socket
                #data,junk_tup = cli_sock.recvfrom(size)
                if(_thread_invoked == 0):
                   
                    #data = recv_from_others(cli_sock,myserver,myserverport,myIP,myport,p)
                    #if(data=='\\exit'):
                        #cli_sock.close()
                        #sys.exit()
                        #print data
                    print "Starting new thread"
                    #thread.start_new_thread(recv_from_others,(cli_sock,myserver,myserverport,myIP,myport,p))
                    
 
            elif tmp == sys.stdin:
                sys.stdout.write('%')   
                sys.stdout.flush()

                line = sys.stdin.readline()
                if line == '\n':
                    break
                
                line = line.strip()
                if(line[0] == '\\') and (line[1] == '@'):
                    """PRIVATE CHAT"""
                    if(':' in line):
                        #print "[CONSOLE] Private chat"
                        #cli_sock.sendto(line,ADDR) FIXME
                        send_packet(cli_sock,line,ADDR,myport)
                    else:
                        print "[CONSOLE] for private chat use as shown below"
                        print "EXAMPLE: @clientname:Hello, This is a private chat"
                elif(line[0] == '\\'):
                    """SPECIAL COMMAND"""
                    check_special_command(line,cli_sock,ADDR,myport,th)
                    #cli_sock.sendto(line,ADDR) FIXME
                    #send_packet(cli_sock,line,ADDR,myport)
                else:
                    """Group Chat"""
                    #print "[CONSOLE] Group Chat"
                    #cli_sock.sendto(line, ADDR)
                    send_packet(cli_sock,line,ADDR,myport)
                    
    if(th!=None):
        th.join()
    cli_sock.close()
    
if __name__ == "__main__":
    main()
    